// Copyright 2024 yehaifeng<yehaifeng@99bill.com>
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build linux && !nodmi
// +build linux,!nodmi

package dmi

import (
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"

	"gitee.com/rogax/kagent/pkg/types"
	// "github.com/prometheus/procfs"
	"github.com/prometheus/procfs/sysfs"
)

type DMIREQUEST struct {
	path    *string
	sysPath *string
}

type DMI struct {
	Manufacturer string `json:"manufacturer"`
	ProductName  string `json:"product_name"`
	SerialNumber string `json:"serial_number"`
	UUID         string `json:"uuid"`
	BiosDate     string `json:"bios_date"`
}

func New(sysPath *string, p *string) *DMIREQUEST {
	return &DMIREQUEST{
		path:    p,
		sysPath: sysPath,
	}
}

func (d *DMIREQUEST) Get() (string, error) {
	dmi := d.getDmiFromSysFS()
	if dmi == nil {
		dmi = d.getDmiFromFile()
	}
	// 解析JSON数据
	jsonData, err := json.Marshal(map[string]DMI{"dmi": *dmi})
	if err != nil {
		log.Println("JSON数据格式化失败: ", err)
		return "", err
	}

	return string(jsonData), nil
}

func (d *DMIREQUEST) getDmiFromSysFS() *DMI {
	fs, err := sysfs.NewFS(*d.sysPath)
	if err != nil {
		log.Printf("failed to open sysfs: %s", err)
		return nil
	}

	dmi, err := fs.DMIClass()
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			log.Printf("Platform does not support Desktop Management Interface (DMI) information, err: %s", err)
			dmi = &sysfs.DMIClass{}
		} else {
			log.Printf("failed to read Desktop Management Interface (DMI) information: %s", err)
			return nil
		}
	}

	return &DMI{
		Manufacturer: strings.ToValidUTF8(*dmi.SystemVendor, "�"),
		ProductName:  strings.ToValidUTF8(*dmi.ProductName, "�"),
		SerialNumber: strings.ToValidUTF8(*dmi.ProductSerial, "�"),
		UUID:         strings.ToValidUTF8(*dmi.ProductUUID, "�"),
		BiosDate:     strings.ToValidUTF8(*dmi.BiosDate, "�"),
	}

}

func (d *DMIREQUEST) getDmiFromFile() *DMI {
	dmi := DMI{}
	regex := regexp.MustCompile(`[\x0a]`)

	bios_date, err := os.ReadFile(*d.path + "/bios_date")
	bios_date = regex.ReplaceAll(bios_date, []byte(""))
	if err != nil {
		log.Println("读取日期失败: ", err)
		bios_date = []byte("07/07/1937")
	}
	dmi.BiosDate = string(bios_date)

	manu_facturer, err := os.ReadFile(*d.path + "/sys_vendor")
	if err != nil {
		log.Println("读取厂商失败: ", err)
		manu_facturer = []byte("")
	}
	dmi.Manufacturer = strings.TrimSpace(string(manu_facturer))
	product_name, err := os.ReadFile(*d.path + "/product_name")
	if err != nil {
		log.Println("读取产品名失败: ", err)
		product_name = []byte("")
	}
	dmi.ProductName = strings.TrimSpace(string(product_name))
	serial, err := os.ReadFile(*d.path + "/product_serial")
	if err != nil {
		log.Println("读取序列号失败: ", err)
		serial = []byte("")
	}
	dmi.SerialNumber = strings.TrimSpace(string(serial))
	uid, err := os.ReadFile(*d.path + "/product_uuid")
	if err != nil {
		log.Println("读取UUID失败: ", err)
		uid = []byte("")
	}
	dmi.UUID = strings.TrimSpace(string(uid))

	return &dmi

	// 解析JSON数据
	// jsonData, err := json.Marshal(map[string]DMI{"dmi": dmi})
	// if err != nil {
	// 	log.Println("JSON数据格式化失败: ", err)
	// 	return "", err
	// }

	// return string(jsonData), nil
}

func (d *DMIREQUEST) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	rsp := types.Response{
		Code:    200,
		Message: "success",
		Data:    nil,
	}

	data, err := d.Get()
	if err != nil {
		log.Println(err)
		rsp.Code = 500
		rsp.Message = err.Error()
		w.WriteHeader(http.StatusInternalServerError)
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(rsp)
		return
	}
	rsp.Data = data
	jsonData, err := json.Marshal(rsp)
	if err != nil {
		log.Println(err)
		rsp.Code = 500
		rsp.Message = err.Error()
		w.WriteHeader(http.StatusInternalServerError)
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(rsp)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}
